import re
import datetime
from rest_framework import serializers
from django.db.models import F
from dateutil.relativedelta import relativedelta
from .models import Orders, GasStationInfo, OilInfo, ReceiptTicket, OrderTicket
from finance_c2c.settings import REGEX_MOBILE
from apps.user_operation.APISerializers import BaseSerializers
from core.tools.CustomFieldsModelSerializer import DynamicFieldsModelSerializer
from .utils import get_actual_time_price
from .models import ExpiryDatePrice
from django.db.models import Sum


# 油价信息
class OilInfoSerializers(DynamicFieldsModelSerializer):
    class Meta:
        model = OilInfo
        fields = ("oilNo", "oilName", "oilType", "priceYfq", "priceGun", "priceOfficial",)


# 初始化加油站
class InitGasSerializers(serializers.ModelSerializer):
    gasTypeDesc = serializers.SerializerMethodField(label="品牌", help_text="品牌")
    oilPriceList = serializers.SerializerMethodField(label="油价列表", help_text="油价列表")

    def get_oilPriceList(self, instance):
        kwargs = {"many": True, "context": self.context}
        return OilInfoSerializers(instance.oilinfo_set.all(), **kwargs).data

    def get_gasTypeDesc(self, instance):
        return instance.get_gasType_display()

    class Meta:
        model = GasStationInfo
        fields = ("gasId", "gasName", "gasTypeDesc", "gasLogoBig", "gasLogoSmall", "gasAddress", "gasAddressLongitude",
                  "gasAddressLatitude", "provinceCode", "cityCode", "countyCode", "provinceName", "cityName",
                  "countyName", "isInvoice", "oilPriceList")


class ApiQueryGasByPhoneSerializers(BaseSerializers):
    gasIds = serializers.CharField(label="加油站id串(用英文逗号隔开)", help_text="加油站id串(用英文逗号隔开)", required=True,
                                   allow_null=False, error_messages={
            "required": "gasIds字段必填"
        })
    mobile = serializers.CharField(max_length=11, min_length=11, help_text="用户手机号", required=True, allow_null=False,
                                   error_messages={
                                       "max_length": "手机号不合法", "min_length": "手机号不合法", "required": "phone字段必填"
                                   })

    def validate_gasIds(self, attrs):
        id_list = attrs.split(",")
        if len(id_list) > 100:
            raise serializers.ValidationError(detail="gasIds太长", code=400)
        return attrs

    def validate_phone(self, attrs):
        if re.match(REGEX_MOBILE, attrs):
            return attrs
        else:
            raise serializers.ValidationError(detail="手机号不合法", code=400)

    def create(self, validated_data):
        gasIds = validated_data["gasIds"]
        mobile = validated_data["mobile"]
        response = self.czb_api.query_price_by_phone(gasIds, mobile)
        # if response.get("code") == 100 and response.get("message") == "根据手机号查询用户无此用户信息":
        #     self.czb_api.platform_login(mobile)  # 去车主邦注册
        #     self.create(validated_data)
        return response

    def update(self, instance, validated_data):
        pass


# 订单创建
class ApiOrdersSerializers(BaseSerializers):
    gasId = serializers.CharField(label="加油id", help_text="加油id")
    gunNumber = serializers.IntegerField(label="油枪号", help_text="油枪号", write_only=True)
    outerOrderId = serializers.CharField(label="订单号", help_text="订单号")
    amountGun = serializers.CharField(label="机显价格(用户输入价格)", help_text="机显价格(用户输入价格)", required=True,
                                      allow_null=False, write_only=True)

    # litre = serializers.CharField(label="升数")
    # priceGun = serializers.CharField(label="枪价")
    # priceUnit = serializers.CharField(label="优惠价")

    def validate_outerOrderId(self, outerOrderId):
        if Orders.objects.filter(outerOrderId=outerOrderId).exists():
            raise serializers.ValidationError("订单号重复")
        else:
            return outerOrderId

    def validate_amountGun(self, amountGun):
        if len(amountGun.split(".")[1]) != 2:
            raise serializers.ValidationError("amountGun需要保留两位小数")
        try:
            amountGun = float(amountGun)
        except Exception as e:
            raise serializers.ValidationError("amountGun数据格式错误")
        return "%.2f" % amountGun

    def submit_orders(self, user, gasId, gunNumber, validated_data, token):
        response = self.czb_api.create_orders(gasId, gunNumber, validated_data["amountGun"],
                                              validated_data["outerOrderId"],
                                              token)
        instance = Orders.objects.create(**validated_data)
        setattr(self, "order", instance)
        if response.get("code") == 200 or response.get("code") == "200":
            result = response.get("result")
            orderId = result.get("orderId")
            orderSn = result.get("orderSn")
            amountPay = result.get("amountPay")
            instance.orderSn = orderSn
            instance.orderId = orderId
            instance.payment = amountPay
            instance.payment_czb = amountPay
            now_time = datetime.datetime.now()
            instance.pay_time = now_time
            instance.update_time = now_time
            instance.channel = self.api_channel
            instance.save()
        elif response.get("code") == 10022 or response.get("code") == "10022":
            self.czb_api.platform_login(user.mobile)
            token = self.czb_api.get_token_from_mc(user.mobile)
            self.submit_orders(user, gasId, gunNumber, validated_data, token)  # 如果是token错误 调自己
        else:
            instance.result = response.get("code")
            instance.message = response.get("message")
            instance.save()
            raise serializers.ValidationError(detail=response.get("message"), code=400)
        return response

    def create(self, validated_data):
        gas_instance = validated_data["gas"]
        gunNumber = validated_data["gunNumber"]
        user = self.context["request"].user
        token = self.czb_api.get_token_from_mc(user.mobile)
        response = self.submit_orders(user, gas_instance.gasId, gunNumber, validated_data, token)
        result = response.get("result")
        result = {"litre": result.get("litre"), "amountPay": result.get("amountPay"),
                  "outerOrderId": self.order.outerOrderId, "result": result.get("result"),
                  "amountGun": result.get("amountGun"), "orderId": result.get("orderId")}
        response["result"] = result
        return response

    def balance_validate(self, amountPay):
        """
        :param amountPay: 实付金额
        :return:
        """
        if self.api_channel.channel_type == 4:
            pass
        if self.api_channel.channel_type == 1:
            if self.api_channel.balance > amountPay:
                pass
            else:
                raise serializers.ValidationError(detail="余额不足", code=400)

    def validate(self, attrs):
        attrs = super(ApiOrdersSerializers, self).validate(attrs)
        gasId = attrs.pop("gasId")
        gunNumber = attrs["gunNumber"]
        user = self.context["request"].user
        try:
            gas_instance = GasStationInfo.objects.get(gasId=gasId)
        except Exception as e:
            raise serializers.ValidationError(detail="gasId有误，未查到", code=400)
        # 获取实时价格
        gun_price_info = get_actual_time_price(gas_instance.gasId, user.mobile, gunNumber, self.czb_api)
        if not isinstance(gun_price_info, dict):
            raise serializers.ValidationError(gun_price_info)
        # 验证余额
        amountGun = attrs["amountGun"]  # 机显金额
        priceGun = gun_price_info.get("priceGun")
        priceYfq = gun_price_info.get("priceYfq")
        oilName = gun_price_info.get("oilName")
        litre = round(float(amountGun) / float(priceGun), 2)  # 升数
        amountPay = round(float(priceYfq) * litre, 2)  # 实付金额
        self.balance_validate(amountPay)
        # 验证余额结束
        attrs["priceGun"] = priceGun
        attrs["amountGun"] = amountGun
        attrs["priceUnit"] = priceYfq
        attrs["litre"] = litre
        attrs["gas"] = gas_instance
        attrs["user"] = user
        attrs["oilName"] = oilName
        return attrs

    class Meta:
        fields = ("appKey", "timeStamp", "sign", "gasId", "gunNumber", "outerOrderId", "amountGun", "litre", "priceGun",
                  "priceUnit")


# 查询订单
class QueryOrdersSerializers(BaseSerializers):
    outerOrderId = serializers.CharField(label="订单号", help_text="订单号", required=True, allow_blank=False,
                                         error_messages={
                                             "required": "orderId不能为空",
                                             "allow_blank": "orderId不能为空",
                                         })

    class Meta:
        fields = ("appKey", "timeStamp", "sign", "outerOrderId",)

    def validate_outerOrderId(self, outerOrderId):
        try:
            order = Orders.objects.get(outerOrderId=outerOrderId)
        except Exception as e:
            print(e)
            raise serializers.ValidationError(detail="没有找到此订单")
        setattr(self, "order", order)
        return outerOrderId

    def create(self, validated_data):
        orderId = self.order.orderId
        response = self.czb_api.query_order(orderId)
        if response.get("code") == 200:
            result = response.get("result")
            orderStatus = result.get("orderStatus")
            order_status = Orders.czbUpOrderStatusMap.get(orderStatus)
            self.order.result = order_status
            self.order.save()
            response["result"]["orderStatus"] = order_status
            orderSn = response["result"].pop("paySn")
            print(response)
            return response
        else:
            raise serializers.ValidationError(response.get("message"))


# 取消订单
class OrdersCancelSerializers(QueryOrdersSerializers):
    def validate_orderId(self, outerOrderId):
        try:
            order = Orders.objects.get(outerOrderId=outerOrderId, user=self.context["request"].user)
            setattr(self, "order", order)
            return outerOrderId
        except Exception as e:
            raise serializers.ValidationError(detail="订单未找到", code=400)

    def create(self, validated_data):
        order = self.order
        if order.order_type == 2:
            order.result = 101
            order.save()
            return {"outerOrderId": validated_data["outerOrderId"], "orderStatus": 101}
        else:
            user = self.context["request"].user
            token = self.czb_api.get_token_from_mc(user.mobile)
            response = self.czb_api.cancel_order(order.orderId, token=token)
            if response.get("code") == 200 or response.get("code") == "200":
                order.result = 101
            else:
                order.message = response.get("message")
            now_time = datetime.datetime.now()
            order.update_time = now_time
            order.save()
            if response.get("code") != 200:
                raise serializers.ValidationError(order.message)
            return response


# 支付回告接口
class PayCallbackSerializers(BaseSerializers):
    outerOrderId = serializers.CharField(label="第三方订单号", allow_null=False, allow_blank=False,
                                         error_messages={"required": "outerOrderId字段不能为空",
                                                         "blank": "outerOrderId字段不能为空",
                                                         "null": "outerOrderId字段不能为空"})
    payAmount = serializers.IntegerField(label="支付金额", error_messages={"required": "payAmount字段不能为空",
                                                                       "blank": "payAmount字段不能为空",
                                                                       "null": "payAmount字段不能为空"})

    def validate_outerOrderId(self, outerOrderId):
        try:
            order = Orders.objects.get(outerOrderId=outerOrderId)
        except Exception as e:
            print(e)
            raise serializers.ValidationError(detail="没有找到此订单", code=400)
        setattr(self, "order", order)
        return outerOrderId

    def submit_pay(self, validated_data, token, user):
        response = self.czb_api.order_pay(self.order.orderSn, int(validated_data["payAmount"]), "200", token)
        if response == 200:
            self.order.czb_pay_status = 1
            self.order.result = 1
            self.order.pay_type = 2
            self.order.payment = "%.2f" % (validated_data["payAmount"] / 100.0)
            self.order.save()
            # 减掉余额
            channel = self.order.channel
            if channel.channel_type == 1:
                channel.balance = F("balance") - self.order.payment_czb
                channel.save()
        elif response == 10022:
            self.czb_api.platform_login(user.mobile)
            token = self.czb_api.get_token_from_mc(user.mobile)
            self.submit_pay(validated_data, token, user)  # 如果是token错误 调自己
        else:
            raise serializers.ValidationError(detail="支付回告提交数据出错", code=400)

    def create(self, validated_data):
        if self.order.order_type == 2:
            self.order.czb_pay_status = 1
            self.order.result = 1
            self.order.pay_type = 2
            self.order.payment = "%.2f" % (validated_data["payAmount"] / 100.0)
            self.order.save()
            # 计算总金额
            sum_payment_czb = Orders.objects.filter(order_type=2, result=1).aggregate(
                sum_payment_czb=Sum("payment_czb")).get(
                "sum_payment_czb")
            sum_payment_czb = int(sum_payment_czb * 100)
            # 筛选折扣
            percent = self.api_channel.channel_vip_price_set.filter(min_cash__lte=sum_payment_czb,
                                                                    max_cash__gt=sum_payment_czb)
            if percent:
                percent = percent.first().percent
            else:
                percent = 1
            self.api_channel.balance = F("balance") - int(self.order.payment_czb * 100 * percent)
            self.api_channel.save()
            user = self.order.user
            now_time = datetime.date.today()
            expiry_date_instance = self.order.expiry_date
            if user.oil_flag_expiry_date and user.oil_flag_expiry_date > now_time:
                user.oil_flag_expiry_date = user.oil_flag_expiry_date + relativedelta(months=expiry_date_instance.month)
            else:
                user.oil_flag_expiry_date = now_time + relativedelta(months=expiry_date_instance.month)
            user.oil_flag = True
            user.save()
        else:
            user = self.context["request"].user
            token = self.czb_api.get_token_from_mc(user.mobile)
            self.submit_pay(validated_data, token, user)  # 如果是token错误 调自己
        return {"code": 200, "message": "ok"}


# 退款
class RefundSerializers(BaseSerializers):
    outerOrderId = serializers.CharField(label="订单号", help_text="订单号",
                                         error_messages={"required": "outerOrderId字段不能为空",
                                                         "blank": "outerOrderId字段不能为空",
                                                         "null": "outerOrderId字段不能为空"})
    refundAmount = serializers.IntegerField(label="退款金额以分单位", help_text="退款金额以分单位",
                                            error_messages={"required": "refundAmount字段不能为空",
                                                            "blank": "refundAmount字段不能为空",
                                                            "null": "refundAmount字段不能为空"})

    def validate_outerOrderId(self, outerOrderId):
        try:
            order = Orders.objects.get(outerOrderId=outerOrderId)
        except Exception as e:
            print(e)
            raise serializers.ValidationError(detail="没有找到此订单", code=400)
        setattr(self, "order", order)
        return outerOrderId

    def submit_refund(self, validated_data, token, user):
        order = self.order
        now_time = datetime.datetime.now()
        order.update_time = now_time
        orderSn = order.orderSn
        response = self.czb_api.order_refund(orderSn, int(validated_data["refundAmount"]),
                                             validated_data["outerOrderId"], token)
        if response.get("code") == 200 or response.get("code") == "200":  # 车主邦申请退款
            order.result = 5  # 支付通道未退款,已经提交到车主邦申请退款
            order.save()
        elif response.get("code") == 10022 or response.get("code") == "10022":
            self.czb_api.platform_login(user.mobile)
            token = self.czb_api.get_token_from_mc(user.mobile)
            self.submit_refund(validated_data, token, user)  # 如果是token错误 调自己
        else:
            order.message = response.get("message")
            order.save()
            raise serializers.ValidationError(detail=response.get("message"), code=400)
        return response

    def create(self, validated_data):
        user = self.context["request"].user
        token = self.czb_api.get_token_from_mc(user.mobile)
        response = self.submit_refund(validated_data, token, user)
        return response


# 购买权益
class EquitySerializers(BaseSerializers):
    month = serializers.IntegerField(help_text="有效期", label="有效期", write_only=True)
    outerOrderId = serializers.CharField(label="订单号", help_text="订单号")

    def validate_outerOrderId(self, outerOrderId):
        if Orders.objects.filter(outerOrderId=outerOrderId).exists():
            raise serializers.ValidationError("订单号重复")
        else:
            return outerOrderId

    def validate_month(self, month):
        month_list = [i.get("month") for i in ExpiryDatePrice.objects.all().values("month")]
        if month in month_list:
            return month
        else:
            serializers.ValidationError(detail="month数据错误")

    def create(self, validated_data):
        month = validated_data["month"]
        outerOrderId = validated_data["outerOrderId"]
        user = self.context["request"].user
        expiry_date_instance = ExpiryDatePrice.objects.get(month=month)
        payment = "%.2f" % (expiry_date_instance.price / 100.0)
        order = self.Meta.model.objects.create(
            expiry_date=expiry_date_instance,
            outerOrderId=outerOrderId,
            user=user,
            order_type=2,
            payment=payment,
            payment_czb=payment,
            channel=self.api_channel
        )
        return order

    class Meta:
        model = Orders
        fields = ("outerOrderId", "month",)


# 直降金额
class DepreciateAmountSerializers(BaseSerializers):
    gasId = serializers.CharField(label="加油站id", help_text="加油站id",
                                  error_messages={"required": "gasId字段必填", "allow_blank": "gasId字段必填"})
    oilNo = serializers.CharField(label="油号", help_text="油号",
                                  error_messages={"required": "oilNo字段必填", "allow_blank": "oilNo字段必填"})
    amountGun = serializers.CharField(label="用户输入金额", help_text="用户输入金额",
                                      error_messages={"required": "amountGun字段必填", "allow_blank": "amountGun字段必填"})

    def validate_amountGun(self, amountGun):
        if len(amountGun.split(".")[1]) != 2:
            raise serializers.ValidationError("amountGun需要保留两位小数")
        try:
            amountGun = float(amountGun)
        except Exception as e:
            raise serializers.ValidationError("amountGun数据格式错误")
        return "%.2f" % amountGun

    def create(self, validated_data):
        gasId = validated_data["gasId"]
        oilNo = validated_data["oilNo"]
        amountGun = validated_data["amountGun"]
        user = self.context["request"].user
        response = self.czb_api.query_depreciate_amount(gasId, oilNo, amountGun, user.mobile)
        return response

    class Meta:
        model = Orders
        fields = ("gasId", "oilNo", "amountGun", "appKey", "timeStamp", "sign")


# 查询开票列表
class QueryInvoiceSerializers(BaseSerializers):
    pageSize = serializers.IntegerField(label="查询订单个数", help_text="查询订单个数", allow_null=True, required=False)
    pageIndex = serializers.IntegerField(label="当前页", help_text="当前页", allow_null=True, required=False)

    def create(self, validated_data):
        user = self.context["request"].user
        token = self.czb_api.get_token_from_mc(user.mobile)
        response = self.czb_api.queryInvoiceListWithPage(token, **validated_data)
        code = response.get("code")
        if code == 200:
            result = response.get("result")
            new_result = []
            for i in result:
                data = dict()
                data["serialNo"] = i.get("serialNo")  # 开票流水号,唯一标志开票请求
                data["invoiceTitleType"] = i.get("invoiceTitleType")  # 开票类型 0:公司 1:个人
                data["buyerTaxNo"] = i.get("buyerTaxNo")  # 购方纳税人识别号
                data["buyerName"] = i.get("buyerName")  # 购方单位名称
                data["buyerAddressPhone"] = i.get("buyerAddressPhone")  # 购方地址及电话
                data["buyerBankAccount"] = i.get("buyerBankAccount")  # 购方开户行及账号
                data["invoiceTotalPriceTax"] = i.get("invoiceTotalPriceTax")  # 价税合计
                data["invoiceStatus"] = i.get("invoiceStatus")  # 票状态 0:待开票 1:开票成功 2:开票失败
                data["invoiceContent"] = i.get("invoiceContent")  # 发票内容
                data["invoiceDate"] = i.get("invoiceDate")  # 开票日期
                data["formatFileUrl"] = i.get("formatFileUrl")  # 电子发票地址
                data["buyerPhone"] = i.get("buyerPhone")  # 购买人手机号
                new_result.append(data)
            response["result"] = new_result
        else:
            raise serializers.ValidationError(response.get("message"), code=400)
        return response

    class Meta:
        model = Orders
        fields = ("pageSize", "pageIndex", "appKey", "timeStamp", "sign")


# 订单开票
class OrderTicketSerializers(BaseSerializers):
    outerOrderId = serializers.CharField(label="订单号", write_only=True,
                                         error_messages={"required": "outerOrderId字段必填",
                                                         "allow_blank": "outerOrderId不能为空"})
    title = serializers.ChoiceField(label="类型", choices=ReceiptTicket.ticketType, write_only=True, required=True,
                                    allow_null=False)
    buyerTaxNo = serializers.CharField(label="购方纳税人识别号", allow_blank=True, required=False, allow_null=True)
    buyerName = serializers.CharField(label="购方单位名称", allow_blank=True, required=False, allow_null=True)
    buyerAddressPhone = serializers.CharField(label="购方地址及电话", allow_blank=True, required=False, allow_null=True)
    buyerBankAccount = serializers.CharField(label="购方开户行及账号", allow_blank=True, required=False, allow_null=True)
    buyerEmail = serializers.CharField(label="购方客户邮箱", allow_blank=False, required=True, allow_null=False)

    def validate_outerOrderId(self, outerOrderId):
        try:
            order = Orders.objects.get(outerOrderId=outerOrderId, result=1)
        except Exception as e:
            raise serializers.ValidationError("订单错误")
        if hasattr(order, "orderticket") and order.orderticket.serialNo:
            raise serializers.ValidationError("此订单已经开过票了")
        return outerOrderId

    def validate_title(self, title):
        if title == 0:
            buyerTaxNo = self.initial_data.get("buyerTaxNo")
            buyerName = self.initial_data.get("buyerName")
            if buyerTaxNo and buyerName:
                return title
            else:
                raise serializers.ValidationError("当tilte是公司的时候，需要填写buyerTaxNo和buyerName")
        return title

    def validate(self, attrs):
        order = Orders.objects.get(outerOrderId=attrs["outerOrderId"], result=1)
        attrs = super(OrderTicketSerializers, self).validate(attrs)
        attrs["orderId"] = order.orderId
        user = self.context["request"].user
        token = self.czb_api.get_token_from_mc(user.mobile)
        response = self.czb_api.gas_insert(token, **attrs)
        if response.get("code") == 200 or response.get("code") == "200":
            attrs.pop("orderId")
            attrs.pop("outerOrderId")
            attrs["serialNo"] = response.get("result").get("serialNo")
            attrs["order"] = order
            attrs["user"] = user
            return attrs
        else:
            raise serializers.ValidationError(response.get("message"))

    def create(self, validated_data):
        instance = OrderTicket.objects.create(**validated_data)
        validated_data["outerOrderId"] = instance.order.outerOrderId
        return {"code": 200, "message": "成功", "result": {"serialNo": instance.serialNo}}

    class Meta:
        model = OrderTicket
        fields = "__all__"
